package com.cltech.frame.query;

import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy;
import org.springframework.data.jpa.repository.query.JpaQueryMethod;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.RepositoryQuery;

import javax.persistence.EntityManager;
import java.lang.reflect.Method;

/**
 * SmartQueryLookupStrategy.
 * @author guanbo
 * @version 1.0.0.0
 */
public class SmartQueryLookupStrategy implements QueryLookupStrategy {
    /**
     * entityManager.
     */
    private final EntityManager entityManager;
    /**
     * jpaQueryLookupStrategy.
     */
    private QueryLookupStrategy jpaQueryLookupStrategy;
    /**
     * extractor.
     */
    private QueryExtractor extractor;

    /**
     * constructor.
     * @param entityManager entityManager
     * @param key key
     * @param extractor extractor
     * @param evaluationContextProvider evaluationContextProvider
     */
    public SmartQueryLookupStrategy(final EntityManager entityManager, final Key key, final QueryExtractor extractor,
                                    final EvaluationContextProvider evaluationContextProvider) {
        this.jpaQueryLookupStrategy = JpaQueryLookupStrategy.create(entityManager, key, extractor, evaluationContextProvider);
        this.extractor = extractor;
        this.entityManager = entityManager;
    }

    /**
     * create queryLookupStrategy.
     * @param entityManager entityManager
     * @param key key
     * @param extractor extractor
     * @param evaluationContextProvider evaluationContextProvider
     * @return QueryLookupStrategy
     */
    public static QueryLookupStrategy create(final EntityManager entityManager, final Key key,
                                             final QueryExtractor extractor,
                                             final EvaluationContextProvider evaluationContextProvider) {
        return new SmartQueryLookupStrategy(entityManager, key, extractor, evaluationContextProvider);
    }

    @Override
    public RepositoryQuery resolveQuery(final Method method, final RepositoryMetadata metadata,
                                        final ProjectionFactory factory,
                                        final NamedQueries namedQueries) {
        if (method.getAnnotation(SmartQuery.class) == null) {
            return jpaQueryLookupStrategy.resolveQuery(method, metadata, factory, namedQueries);
        } else {
            return new SmartJpaQuery(method, new JpaQueryMethod(method, metadata, factory, extractor), entityManager);
        }
    }
}
